package com.gitee.qdbp.general.trade.biz.order.main.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.result.ResultCode;
import com.gitee.qdbp.base.model.reusable.UnitInteger;
import com.gitee.qdbp.base.system.model.IAccount;
import com.gitee.qdbp.general.common.api.settings.service.ISystemConfigItemQueryer;
import com.gitee.qdbp.general.common.enums.ConfigScene;
import com.gitee.qdbp.general.trade.api.order.main.model.OrderFormBean;
import com.gitee.qdbp.general.trade.api.order.main.model.OrderFormUpdate;
import com.gitee.qdbp.general.trade.api.order.main.model.OrderFormWhere;
import com.gitee.qdbp.general.trade.api.order.main.model.OrderItemBase;
import com.gitee.qdbp.general.trade.api.order.main.model.OrderItemBean;
import com.gitee.qdbp.general.trade.api.order.main.service.IOrderMainExecutor;
import com.gitee.qdbp.general.trade.biz.order.main.basic.OrderFormBasic;
import com.gitee.qdbp.general.trade.biz.order.main.basic.OrderItemBasic;
import com.gitee.qdbp.general.trade.biz.order.main.service.AmountTools.AmountBean;
import com.gitee.qdbp.general.trade.enums.OrderState;
import com.gitee.qdbp.tools.specialized.KeywordHandler;
import com.gitee.qdbp.tools.utils.DateTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * 订单主业务处理类
 *
 * @author zhh
 * @version 170729
 */
@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public class OrderMainExecutor implements IOrderMainExecutor {

    /** 日志对象 **/
    private static final Logger log = LoggerFactory.getLogger(OrderMainExecutor.class);

    @Autowired
    private OrderFormBasic orderFormBasic;
    @Autowired
    private OrderItemBasic orderItemBasic;
    @Autowired
    private ISystemConfigItemQueryer systemConfigQueryer;

    /** 创建订单 **/
    public String create(OrderFormBean orderForm, List<OrderItemBase> orderItems, IAccount operator)
            throws ServiceException {

        String msg = "Failed to CreateOrder. ";
        { // 参数校验
            if (VerifyTools.isBlank(orderForm)) {
                log.error(msg + "params is null: orderForm");
                throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
            }
            if (VerifyTools.isBlank(orderForm.getOrderType())) {
                log.error(msg + "params is null: orderType");
                throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
            }
        }
        Date createTime;
        { // 设置默认值
            orderForm.setPaidAmount(0D); // 已支付金额
            orderForm.setDeliverQuantity(0); // 已发货件数
            orderForm.setOrderState(OrderState.PENDING); // 订单状态
            // 运费金额
            if (VerifyTools.isBlank(orderForm.getFreightAmount())) {
                orderForm.setFreightAmount(0D);
            }
            // 创建时间
            if (VerifyTools.isBlank(orderForm.getCreateTime())) {
                orderForm.setCreateTime(createTime = new Date());
            } else {
                createTime = orderForm.getCreateTime();
            }
        }

        KeywordHandler keywords = null;
        if (VerifyTools.isBlank(orderForm.getQueryKeywords())) {
            keywords = KeywordHandler.newInstance();
        }
        if (VerifyTools.isBlank(orderItems)) {
            // 如果没有订单明细就必须传入商品内容和商品金额
            if (VerifyTools.isBlank(orderForm.getOrderContent())) {
                log.error(msg + "params is null: orderContent");
                throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
            }
            if (VerifyTools.isBlank(orderForm.getGoodsAmount())) {
                log.error(msg + "params is null: goodsAmount");
                throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
            }
            // 计算单价总价折扣: 只有单价就计算总价, 只有总价就计算单价, 有单价和总价就计算折扣, 都有就检查是否正确
            AmountBean temp = new AmountBean();
            temp.setPrice(orderForm.getGoodsAmount());
            temp.setDiscount(orderForm.getDiscountAmount());
            temp.setFreight(orderForm.getFreightAmount());
            temp.setAmount(orderForm.getTotalAmount());
            AmountTools.calculate(temp);
            orderForm.setGoodsAmount(temp.getPrice());
            orderForm.setDiscountAmount(temp.getDiscount());
            orderForm.setFreightAmount(temp.getFreight());
            orderForm.setTotalAmount(temp.getAmount());
            if (keywords != null) {
                keywords.addText(orderForm.getOrderContent());
            }
        } else {
            double itemsAmount = 0D;
            int totalQuantity = 0;
            OrderItemBase main = null;
            for (OrderItemBase item : orderItems) {
                // 校验参数
                if (VerifyTools.isBlank(item.getGoodsTitle())) {
                    log.error(msg + "params is null: GoodsTitle");
                    throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
                }
                // 购买数量
                if (VerifyTools.isBlank(item.getQuantity())) {
                    item.setQuantity(1);
                }

                // 计算单价数量金额折扣
                AmountBean temp = new AmountBean();
                temp.setPrice(item.getGoodsPrice());
                temp.setQuantity(item.getQuantity());
                temp.setDiscount(item.getDiscountAmount());
                temp.setAmount(item.getGoodsAmount());
                AmountTools.calculate(temp);
                item.setGoodsPrice(temp.getPrice());
                item.setQuantity(temp.getQuantity());
                item.setDiscountAmount(temp.getDiscount());
                item.setGoodsAmount(temp.getAmount());

                itemsAmount += item.getGoodsAmount();
                totalQuantity += item.getQuantity();

                if (main == null || main.getGoodsAmount() < item.getGoodsAmount()) {
                    main = item;
                }
                if (keywords != null) {
                    keywords.addText(item.getGoodsName(), item.getGoodsTitle());
                    keywords.addPlain(item.getModelNumber());
                }
            }

            if (VerifyTools.isBlank(orderForm.getOrderContent())) {
                // 订单内容: 多个商品取总价最高的那个,加等几件
                String orderContent = main.getGoodsTitle();
                if (orderItems.size() == 1) {
                    if (totalQuantity > 1) {
                        orderContent += "*" + totalQuantity;
                    }
                } else if (orderItems.size() > 1) {
                    orderContent += "等" + totalQuantity + "件";
                }
                orderForm.setOrderContent(orderContent);
            }

            // 商品总件数
            if (VerifyTools.isBlank(orderForm.getTotalQuantity())) {
                orderForm.setTotalQuantity(totalQuantity);
            } else {
                if (orderForm.getTotalQuantity() != totalQuantity) {
                    log.error(msg + "TotalQuantity[{}] error, expect[{}]", orderForm.getTotalQuantity(), totalQuantity);
                    throw new ServiceException(ResultCode.PARAMETER_VALUE_ERROR);
                }
            }
            // 商品总金额
            if (VerifyTools.isBlank(orderForm.getGoodsAmount())) {
                orderForm.setGoodsAmount(itemsAmount);
            } else {
                if (orderForm.getGoodsAmount() != itemsAmount) {
                    log.error(msg + "GoodsAmount[{}] error, expect[{}]", orderForm.getGoodsAmount(), itemsAmount);
                    throw new ServiceException(ResultCode.PARAMETER_VALUE_ERROR);
                }
            }
            // 商品金额 已知, 如果没有总价就计算总价, 没有折扣就计算折扣, 如果都有就检查是否正确
            AmountBean temp = new AmountBean();
            temp.setPrice(orderForm.getGoodsAmount());
            temp.setDiscount(orderForm.getDiscountAmount());
            temp.setFreight(orderForm.getFreightAmount());
            temp.setAmount(orderForm.getTotalAmount());
            AmountTools.calculate(temp);
            orderForm.setGoodsAmount(temp.getPrice());
            orderForm.setDiscountAmount(temp.getDiscount());
            orderForm.setFreightAmount(temp.getFreight());
            orderForm.setTotalAmount(temp.getAmount());
        }

        // 生成查询关键字
        if (keywords != null) {
            orderForm.setQueryKeywords(keywords.toString());
        }
        // 过期时间
        if (VerifyTools.isBlank(orderForm.getExpireTime())) {
            // 根据配置项设置订单过期时间
            fillOrderExpireTime(orderForm);
        }

        // 向订单主表插入记录
        orderFormBasic.create(orderForm);

        if (VerifyTools.isNotBlank(orderItems)) {
            List<OrderItemBean> list = new ArrayList<>();
            for (OrderItemBase item : orderItems) {
                OrderItemBean bean = item.to(OrderItemBean.class);
                // bean.setId(null); // 主键
                bean.setDataId(orderForm.getDataId()); // 关联业务ID
                bean.setOrderId(orderForm.getId());
                bean.setTenantCode(orderForm.getTenantCode()); // 商家租户编号
                bean.setUserId(orderForm.getUserId()); // 消费者用户ID
                bean.setOrderId(orderForm.getId()); // 订单ID
                bean.setOrderType(orderForm.getOrderType()); // 订单类型(0.捐款订单|1.商品订单)
                bean.setCreateTime(createTime); // 创建时间
            }
            // 向订单明细表插入记录
            orderItemBasic.create(list);
        }

        // TODO description add to ProcessingRecord
        return orderForm.getId();
    }

    // 根据配置项设置订单过期时间
    private void fillOrderExpireTime(OrderFormBean orderForm) {

        String tenantCode = orderForm.getTenantCode();
        Date createTime = orderForm.getCreateTime();
        ConfigScene scene = ConfigScene.manager;
        String key = "order.expire.time." + orderForm.getOrderType().name().toLowerCase();
        TimeUnit unit = TimeUnit.DAYS;
        int value = 1;
        try {
            UnitInteger temp = systemConfigQueryer.findObjectValue(scene, tenantCode, key, UnitInteger.class);
            if (temp != null) {
                unit = toTimeUnit(temp.getUnit());
                value = temp.getValue();
            }
        } catch (Exception e) {
            log.error("ConfigValueFormatError: scene={}, key={}", scene, key, e);
        }
        Date expireTime;
        switch (unit) {
        case DAYS:
            expireTime = DateTools.toLastTime(DateTools.addDay(createTime, value), Calendar.DAY_OF_MONTH);
            break;
        case HOURS:
            expireTime = DateTools.toLastTime(DateTools.addHour(createTime, value), Calendar.HOUR_OF_DAY);
            break;
        case MINUTES:
            expireTime = DateTools.toLastTime(DateTools.addMinute(createTime, value), Calendar.MINUTE);
            break;
        case SECONDS:
            expireTime = DateTools.toLastTime(DateTools.addSecond(createTime, value), Calendar.SECOND);
            break;
        default:
            expireTime = DateTools.addMillisecond(createTime, value);
            break;
        }
        orderForm.setExpireTime(expireTime);
    }

    private TimeUnit toTimeUnit(String value) {
        TimeUnit unit = null;
        for (TimeUnit item : TimeUnit.values()) {
            if (value == item.name()) {
                unit = item;
                break;
            }
        }
        if (unit == null) {
            throw new IllegalArgumentException("Value [" + value + "] can't convert to TimeUnit.");
        }
        if (VerifyTools.isExists(unit, TimeUnit.NANOSECONDS, TimeUnit.MICROSECONDS)) {
            throw new IllegalArgumentException("Value [" + value + "] isn't supported.");
        }
        return unit;
    }

    /** 修改订单金额(总金额和运费) **/
    public void updateAmount(String orderId, Double totalAmount, Double freightAmount, IAccount operator)
            throws ServiceException {

        if (totalAmount == null && freightAmount == null) {
            return;
        }

        String msg = "Failed to update amount of order. ";
        if (VerifyTools.isBlank(orderId)) {
            log.error(msg + "params is null: orderId");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        // 查询订单
        OrderFormBean older = findByIdThrowOnNotExists(orderId);

        OrderFormUpdate ud = new OrderFormUpdate();
        OrderFormWhere where = ud.getWhere(true);
        where.setId(orderId);
        if (totalAmount != null && totalAmount != older.getTotalAmount()) { // 修改总金额
            // 运费
            double freight = freightAmount != null ? freightAmount : older.getFreightAmount();
            // 计算折扣: 折扣=总金额-商品金额-运费
            double discountAmount = totalAmount - older.getGoodsAmount() - freight;
            ud.setTotalAmountAdd(totalAmount - older.getTotalAmount());
            if (discountAmount != older.getDiscountAmount()) {
                ud.setDiscountAmountAdd(discountAmount - older.getDiscountAmount());
            }
            if (discountAmount != older.getDiscountAmount()) {
                ud.setFreightAmountAdd(freight - older.getFreightAmount());
            }
        } else if (freightAmount != null && freightAmount != older.getFreightAmount()) { // 只修改运费
            ud.setFreightAmountAdd(freightAmount - older.getFreightAmount());
            ud.setTotalAmountAdd(older.getTotalAmount() + freightAmount - older.getFreightAmount());
        } else { // 总金额和运费都没有变动
            return;
        }

        // 修改数据库记录
        int rows = orderFormBasic.update(ud, false);
        if (rows == 0) {
            log.error(msg + "affected rows is 0. orderId={}.", orderId);
            throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
        }

        // TODO description add to ProcessingRecord
    }

    /** 取消订单(待支付变成已取消) **/
    @Override
    public void cancel(String id, IAccount operator) throws ServiceException {
        String msg = "Failed to cancel OrderForm. ";

        OrderFormBean older = findByIdThrowOnNotExists(id);
        OrderState state = older.getOrderState();
        if (state != OrderState.PENDING) {
            log.error(msg + "record state error. id={}, state={}", id, state);
            throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
        }

        // 组装提交参数
        OrderFormUpdate ud = new OrderFormUpdate();
        ud.setOrderState(OrderState.CANCELED);

        OrderFormWhere where = new OrderFormWhere();
        ud.setWhere(where);
        where.setId(id);
        where.setOrderState(OrderState.PENDING);

        // 更新vml_order_form表的记录
        int rows = orderFormBasic.update(ud, false);
        if (rows == 0) {
            log.error(msg + "affected rows is 0. id={}.", id);
            throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
        }

        // TODO description add to ProcessingRecord
    }

    /** 删除无效订单 **/
    @Override
    public void deleteIneffectiveRecord(String id, IAccount operator) throws ServiceException {
        String msg = "Failed to delete ineffective OrderForm. ";

        // 组装提交参数
        OrderFormWhere where = new OrderFormWhere();
        where.setId(id);
        where.addOrderState(OrderState.PENDING, OrderState.CANCELED);

        // 删除vml_order_form表的记录
        int rows = orderFormBasic.delete(where, false);
        if (rows == 0) {
            log.error(msg + "affected rows is 0. id={}.", id);
            throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
        }

        // TODO description add to ProcessingRecord
    }

    /** 删除有效订单 **/
    @Override
    public void deleteEffectiveRecord(String id, IAccount operator) throws ServiceException {
        String msg = "Failed to delete effective OrderForm. ";

        // 组装提交参数
        OrderFormWhere where = new OrderFormWhere();
        where.setId(id);
        where.addOrderState(OrderState.PAID, OrderState.DELIVERED, OrderState.FINISHED);

        // 删除vml_order_form表的记录
        int rows = orderFormBasic.delete(where, false);
        if (rows == 0) {
            log.error(msg + "affected rows is 0. id={}.", id);
            throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
        }

        // TODO description add to ProcessingRecord
    }

    @Override
    public void deliverByCarrier(String orderId, int deliverQuantity, String newQueryKeywords) throws ServiceException {
        String msg = "Failed to update DeliverState. ";

        OrderFormUpdate ud = new OrderFormUpdate();
        ud.setOrderState(OrderState.DELIVERED);
        ud.setDeliverQuantityAdd(deliverQuantity);
        if (VerifyTools.isNotBlank(newQueryKeywords)) {
            ud.setQueryKeywords(newQueryKeywords);
        }
        OrderFormWhere where = ud.getWhere(true);
        where.setId(orderId);
        where.setOrderState(OrderState.PAID);

        // 更新vml_order_form表的记录
        int rows = orderFormBasic.update(ud, false);
        if (rows == 0) {
            log.error(msg + "affected rows is 0. orderId={}.", orderId);
            throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
        }
    }

    /** 根据ID查找订单, 如果不存在则报错 **/
    private OrderFormBean findByIdThrowOnNotExists(String orderId) throws ServiceException {
        VerifyTools.requireNotBlank(orderId, "orderId");

        OrderFormWhere model = new OrderFormWhere();
        model.setId(orderId);

        OrderFormBean bean = orderFormBasic.find(model);

        if (bean == null) {
            log.warn("OrderForm not found, orderId={}", orderId);
            throw new ServiceException(ResultCode.RECORD_NOT_EXIST);
        }
        return bean;
    }

    //    /** 订单主查询 */
    //    public PageList<OrderFormBean> list(OrderFormWhere where, OrderPaging paging) throws ServiceException {
    //        return orderFormBasic.list(where, paging);
    //    }
}
